using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Drawing;

namespace MKDS_Course_Editor
{
    class narc
    {
        public class directory
        {
            public directory(string name, int id)
            {
                this.name = name;
                this.id = id;
            }
            public List<directory> subdirs = new List<directory>();
            public directory getDirById(int id)
            {
                for (int i = 0; i < subdirs.Count; i++)
                {
                    if (subdirs[i].id == id)
                    {
                        return subdirs[i];
                    }
                }
                for (int i = 0; i < subdirs.Count; i++)
                {
                    if (subdirs[i].getDirById(id) != null)
                    {
                        return subdirs[i].getDirById(id);
                    }
                }
                return null;
            }
            public void extract(string path)
            {
                for (int i = 0; i < subdirs.Count; i++)
                {
                    Directory.CreateDirectory(path + "\\" + subdirs[i].name);
                }
                for (int i = 0; i < Files.Count; i++)
                {
                    File.Create(path + "\\" + Files[i].name).Close();
                    File.WriteAllBytes(path + "\\" + Files[i].name, Files[i].content);
                }
                for (int i = 0; i < subdirs.Count; i++)
                {
                    subdirs[i].extract(path + "\\" + subdirs[i].name);
                }
            }
            public bool setFile(byte[] bytes, int id)
            {
                for (int i = 0; i < Files.Count; i++)
                {
                    if (Files[i].id == id)
                    {
                        Files[i].content = bytes;
                        return true;
                    }
                }
                for (int i = 0; i < subdirs.Count; i++)
                {
                    if (subdirs[i].setFile(bytes, id))
                    {
                        return true;
                    }
                }
                return false;
            }
			public bool setFile(file f)
			{
				for (int i = 0; i < Files.Count; i++)
				{
					if (Files[i].id == f.id)
					{
						Files[i] = f;
						return true;
					}
				}
				for (int i = 0; i < subdirs.Count; i++)
				{
					if (subdirs[i].setFile(f))
					{
						return true;
					}
				}
				return false;
			}
			public int NrOfFiles
			{
				get
				{
					int nr = Files.Count;
					for (int i = 0; i < subdirs.Count; i++)
					{
						nr += subdirs[i].NrOfFiles;
					}
					return nr;
				}
			}
			public int NrOfDirs
			{
				get
				{
					int nr = subdirs.Count;
					for (int i = 0; i < subdirs.Count; i++)
					{
						nr += subdirs[i].NrOfDirs;
					}
					return nr;
				}
			}
			public file getFile(int id)
			{
				for (int i = 0; i < Files.Count; i++)
				{
					if (Files[i].id == id)
					{
						return Files[i];
					}
				}
				for (int i = 0; i < subdirs.Count; i++)
				{
					file f = subdirs[i].getFile(id);
					if (f != null)
					{
						return f;
					}
				}
				return null;
			}
			public TreeNode[] getNodes(ContextMenuStrip nsbmd, ContextMenuStrip Default)
			{
				List<TreeNode> t = new List<TreeNode>();
				for (int i = 0; i < subdirs.Count; i++)
				{
					TreeNode tn = new TreeNode(subdirs[i].name);
					tn.ImageIndex = 3;
					tn.SelectedImageIndex = 3;
					t.Add(tn);
				}
				for (int i = 0; i < Files.Count; i++)
				{
					TreeNode tn = new TreeNode(Files[i].name);
					tn.ContextMenuStrip = Default;
					switch (Path.GetExtension(Files[i].name).ToLower())
					{
						case ".nsbtx":
							tn.ImageIndex = 1;
							tn.SelectedImageIndex = 1;
							break;
						case ".nsbmd":
							tn.ImageIndex = 2;
							tn.SelectedImageIndex = 2;
							tn.ContextMenuStrip = nsbmd;
							break;
						case ".nsbtp":
						case ".nsbta":
							tn.ImageIndex = 4;
							tn.SelectedImageIndex = 4;
							break;
						case ".nkm":
							tn.ImageIndex = 5;
							tn.SelectedImageIndex = 5;
							break;
						case ".kcl":
							tn.ImageIndex = 6;
							tn.SelectedImageIndex = 6;
							break;
						case ".nclr":
							tn.ImageIndex = 7;
							tn.SelectedImageIndex = 7;
							break;
						case ".ncgr":
							tn.ImageIndex = 8;
							tn.SelectedImageIndex = 8;
							break;
						case ".nscr":
							tn.ImageIndex = 9;
							tn.SelectedImageIndex = 9;
							break;
						case ".ncer":
							tn.ImageIndex = 10;
							tn.SelectedImageIndex = 10;
							break;
						case ".nanr":
							tn.ImageIndex = 11;
							tn.SelectedImageIndex = 11;
							break;
					}
					if (libWiiSharp.Lz77.IsLz77Compressed(Files[i].content))
					{
						tn.ForeColor = Color.Blue;
					}
					t.Add(tn);
				}
				for (int i = 0; i < subdirs.Count; i++)
				{
					t[i].Nodes.AddRange(subdirs[i].getNodes(nsbmd, Default));
				}
				return t.ToArray();
			}
			public void getNarcData(ref EndianBinaryWriter er2, ref EndianBinaryWriter er4, bool isRoot, sbyte depth, directory Root, ref Int16 items, ref List<sbyte> mapID_,ref sbyte mapID, int j = 0)
			{
				if (isRoot)
				{
					for (int i = 0; i < subdirs.Count; i++)
					{
						mapID_.Add(mapID);
						er2.Write((sbyte)(subdirs[i].name.Length + 0x80));
						er2.Write(subdirs[i].name, Encoding.ASCII, false);
						er2.Write(mapID);
						er2.Write((byte)0xF0);
						mapID += (sbyte)(subdirs[i].subdirs.Count + 1);
					}
					for (int i = 0; i < Files.Count; i++)
					{
						//FileInfo f = new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
						er2.Write((sbyte)Files[i].name.Length);
						er2.Write(Files[i].name, Encoding.ASCII, false);
						items += 1;
					}
					List<sbyte> mapID_2 = new List<sbyte>();
					sbyte mapID2 = (sbyte)(depth + 1);
					for (int i = 0; i < subdirs.Count; i++)
					{
						er2.Write((byte)0x00);
						er4.Write((Int32)er2.BaseStream.Position + (8 + (Root.NrOfDirs * 0x8)));
						er4.Write(items);
						er4.Write((sbyte)0);
						er4.Write((byte)0xF0);
						subdirs[i].getNarcData(ref er2, ref er4, false, (sbyte)(depth + 1), Root,ref items,ref mapID_2, ref mapID2, i);
					}
				}
				else
				{
					for (int i = 0; i < subdirs.Count; i++)
					{
						mapID_.Add(mapID);
						er2.Write((sbyte)(subdirs[i].name.Length + 0x80));
						er2.Write(subdirs[i].name, Encoding.ASCII, false);
						er2.Write(mapID);
						er2.Write((byte)0xF0);
						mapID += (sbyte)(subdirs[i].subdirs.Count + 1);
					}
					if (j != Root.subdirs.Count && depth == 2)
					{
						mapID += 1;
					}
					for (int i = 0; i < Files.Count; i++)
					{
						//FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
						er2.Write((sbyte)Files[i].name.Length);
						er2.Write(Files[i].name, Encoding.ASCII, false);
						items += 1;
					}
					sbyte mapID2 = (sbyte)(depth + 1);
					List<sbyte> mapID_2 = new List<sbyte>();
					for (int i = 0; i < subdirs.Count; i++)
					{
						er2.Write((byte)0x00);
						er4.Write((Int32)er2.BaseStream.Position + (8 + (Root.NrOfDirs * 0x8)));
						er4.Write(items);
						er4.Write((sbyte)(mapID_[i]));//Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length);
						er4.Write((byte)0xF0);
						subdirs[i].getNarcData(ref er2, ref er4, false, (sbyte)(depth + 1), Root, ref items, ref mapID_2, ref mapID2);
					}
				}
			}
			public void writeFileData(ref EndianBinaryWriter er3)
			{
				for (int i = 0; i < Files.Count; i++)
				{
					er3.Write(Files[i].content, 0, (int)Files[i].content.Length);
					while (true)
					{
						if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
						{
							break;
						}
						else
						{
							er3.Write((byte)0xFF);
						}
					}
				}
				for (int i = 0; i < subdirs.Count; i++)
				{
					subdirs[i].writeFileData(ref er3);
				}
			}
			public string name;
            public int id;
            public List<file> Files = new List<file>();
        }
        public class file
        {
            public file(string name, int id)
            {
                this.name = name;
                this.id = id;
            }
            public int id;
            public string name;
            public byte[] content;
        }
        public static directory unpack(string infile, string outdir)
        {
            int filesize;
            int headersize;
            int nSections;
            int btafsize;
            int nfiles;
            int btnfsize;
            List<int> boffset = new List<int>();
            List<int> eoffset = new List<int>();
            int dirstartoffset;
            int ffposition;
            int ndir;
            int foffset;
            int ffposition2;
            int pd;
            List<string> filenames = new List<string>();
            List<int> files_dir = new List<int>();
            List<string> dirnames = new List<string>();
            List<int> dir_id = new List<int>();
            List<int> dir_dir = new List<int>();

            directory Root = new directory("root", 0);
            directory curdir = Root;

            int curdirid;
            int gmifsize;
            int pos;
			bool usenames = true;
            EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(infile), Endianness.LittleEndian);
            if (er.ReadString(Encoding.ASCII, 4) == "NARC")//Stamp (NARC) "Nitro ARChive".
            {
                er.ReadBytes(4);
                filesize = er.ReadInt32();
                headersize = er.ReadInt16();
                nSections = er.ReadInt16();
                if (er.ReadString(Encoding.ASCII, 4) == "BTAF")//Stamp (FATB) "File Allocation Table Block".
                {
                    btafsize = er.ReadInt32();
                    nfiles = er.ReadInt32();
                    for (int i = 0; i < nfiles; i++)
                    {
                        boffset.Add(er.ReadInt32());
                        eoffset.Add(er.ReadInt32());
                    }
                    if (er.ReadString(Encoding.ASCII, 4) == "BTNF")//Stamp (FNTB) "File Name Table Block".
                    {
                        btnfsize = er.ReadInt32();
						if (btnfsize == 0x10)
						{
							for (int i = 0; i < nfiles; i++)
							{
								Root.Files.Add(new file("Unknown file " + i.ToString()+".bin", i));
							}
							usenames = false;
							er.ReadBytes(8);
							goto GMIF;
						}
                        pos = (int)er.BaseStream.Position;
                        dirstartoffset = er.ReadInt32();
                        ffposition = er.ReadInt16();
                        ndir = er.ReadInt16();
                        foffset = er.ReadInt32();
                        ffposition2 = er.ReadInt16();
                        pd = er.ReadInt16();
                        curdirid = 0;
                        er.BaseStream.Position = pos + dirstartoffset;
                        for (int i = 0; i < nfiles+(ndir-1); i++)
                        {
                            byte size = er.ReadByte();
                            if (size < 0x80 && size > 0x00)
                            {
                                filenames.Add(er.ReadString(Encoding.ASCII, size));
                                files_dir.Add(curdirid);
                                curdir.Files.Add(new file(filenames.Last(), files_dir.Count-1));
                            }
                            else if (size > 0x80 && size < 0xB0)
                            {
                                size -= 0x80;
                                dirnames.Add(er.ReadString(Encoding.ASCII, size));
                                dir_id.Add(er.ReadByte());
                                dir_dir.Add(curdirid);
                                er.ReadByte();
                                curdir.subdirs.Add(new directory(dirnames.Last(), dir_id.Last()));
                            }
                            else
                            {
                                curdirid += 1;
                                curdir = Root.getDirById(curdirid);
                                i -= 1;
                            }
                        }
                    GMIF:
                        if (er.ReadString(Encoding.ASCII, 4) == "GMIF")//Stamp (FIMG) "File IMaGes".
                        {
                            gmifsize = er.ReadInt32();
                            pos = (int)er.BaseStream.Position;
                            /*for (int i = 0; i < ndir-1; i++)
                            {
                                if (dir_dir[i] == 0)
                                {
                                    Directory.CreateDirectory(outdir + "\\" + dirnames[i]);
                                }
                                else
                                {
                                    try
                                    {
                                        Directory.CreateDirectory(outdir + "\\" + dirnames[dir_id.IndexOf(dir_dir[dir_id.IndexOf(dir_dir[i])])] + "\\" + dirnames[i]);
                                    }
                                    catch
                                    {
                                        Directory.CreateDirectory(outdir + "\\" + dirnames[dir_id.IndexOf(dir_dir[i])] + "\\" + dirnames[i]);
                                    }
                                }
                            }*/
                            for (int i = 0; i < nfiles; i++)
                            {
                                er.BaseStream.Position = pos + boffset[i];
                                Root.setFile(er.ReadBytes(eoffset[i] - boffset[i]), i);
								if (!usenames)
								{
									file f = Root.getFile(i);
									byte[] data = f.content;
									switch (Convert.ToChar(data[0]).ToString() + Convert.ToChar(data[1]).ToString() + Convert.ToChar(data[2]).ToString() + Convert.ToChar(data[3]).ToString())
									{
										case "NARC":
											f.name = f.name.Replace(".bin", ".narc");
											break;
										case "NKMD":
											f.name = f.name.Replace(".bin", ".nkm");
											break;
										case "BMD0":
											f.name = f.name.Replace(".bin", ".nsbmd");
											break;
										case "BMA0":
											f.name = f.name.Replace(".bin", ".nsbma");
											break;
										case "BTA0":
											f.name = f.name.Replace(".bin", ".nsbta");
											break;
										case "BVA0":
											f.name = f.name.Replace(".bin", ".nsbva");
											break;
										case "BCA0":
											f.name = f.name.Replace(".bin", ".nsbca");
											break;
										case "BTP0":
											f.name = f.name.Replace(".bin", ".nsbtp");
											break;
										case "BTX0":
											f.name = f.name.Replace(".bin", ".nsbtx");
											break;
										case "SDAT":
											f.name = f.name.Replace(".bin", ".sdat");
											break;
									}
									Root.setFile(f);
								}
                                /*er.BaseStream.Position = pos + boffset[i];
                                if (files_dir[i] == 0)
                                {
                                    FileStream f =File.Create(outdir + "\\" + filenames[i]);
                                    f.Close();
                                    File.WriteAllBytes(outdir + "\\" + filenames[i], er.ReadBytes(eoffset[i] - boffset[i]));
                                }
                                else if (dir_dir[dir_id.IndexOf(files_dir[i])] == 0)
                                {
                                    FileStream f = File.Create(outdir + "\\" + dirnames[dir_id.IndexOf(files_dir[i])] + "\\" + filenames[i]);
                                    f.Close();
                                    File.WriteAllBytes(outdir + "\\" + dirnames[dir_id.IndexOf(files_dir[i])] + "\\" + filenames[i], er.ReadBytes(eoffset[i] - boffset[i]));
                                }
                                else
                                {
                                    FileStream f = File.Create(outdir + "\\" + dirnames[dir_id.IndexOf(dir_dir[dir_id.IndexOf(files_dir[i])])] + "\\" + dirnames[dir_id.IndexOf(files_dir[i])] + "\\" + filenames[i]);
                                    f.Close();
                                    File.WriteAllBytes(outdir + "\\" + dirnames[dir_id.IndexOf(dir_dir[dir_id.IndexOf(files_dir[i])])] + "\\" + dirnames[dir_id.IndexOf(files_dir[i])] + "\\" + filenames[i], er.ReadBytes(eoffset[i] - boffset[i]));
                                }*/
                            }
                            Root.extract(outdir);
                        }
                        else
                        {
                            er.BaseStream.Position -= 3;
                            goto GMIF;
                            MessageBox.Show("Error3", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Error2", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    MessageBox.Show("Error1", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                MessageBox.Show("It isn't a narc file, or it is compressed.", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            er.Close();
			return Root;
        }
        //private static string getpath(int depht)
        //{
            
        //}
        public static void pack(directory indir, string outfile)
        {
            File.Delete(outfile);
            EndianBinaryWriter er = new EndianBinaryWriter(File.OpenWrite(outfile), Endianness.LittleEndian);
            //header
            er.Write("NARC", Encoding.ASCII, false);
            er.Write(new byte[]{0xFE,0xFF,0x00,0x01}, 0, 4);
            er.Write((Int32)0); //write later
            er.Write((Int16)16);
            er.Write((Int16)3);
            //btaf
            er.Write("BTAF", Encoding.ASCII, false);
			Int32 numfiles = indir.NrOfFiles;//Directory.GetFiles(indir, "*.*", SearchOption.AllDirectories).Length;
            er.Write((Int32)0xC + (numfiles * 8));
            er.Write(numfiles);
            int pos = 0;
            for (int i = 0; i < numfiles; i++)
            {
                er.Write((Int32)pos);
				pos += (Int32)(indir.getFile(i).content.Length);//new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.AllDirectories)[i]).Length);
                er.Write((Int32)pos);
                while (true)
                {
                    if (CountDecimalPlaces((float)pos / 4F) == 0)
                    {
                        break;
                    }
                    else
                    {
                        pos+=1;
                    }
                }
            }
            //BTNF
            MemoryStream ms = new MemoryStream();
            EndianBinaryWriter er2 = new EndianBinaryWriter(ms, Endianness.LittleEndian);
            MemoryStream ms3 = new MemoryStream();
            EndianBinaryWriter er4 = new EndianBinaryWriter(ms3, Endianness.LittleEndian);
            er4.Write((Int32)(8 + indir.NrOfDirs*0x8));
            er4.Write((Int16)0);
			er4.Write((Int16)(indir.NrOfDirs + 1));
            List<sbyte> mapID_ = new List<sbyte>();
            List<sbyte> mapID2_ = new List<sbyte>();
            List<sbyte> mapID3_ = new List<sbyte>();
            sbyte mapID = 1;
            sbyte mapID2 = 2;
            sbyte mapID3 = 3;
            Int16 items = 0;
			indir.getNarcData(ref er2, ref er4, true, 1, indir,ref items,ref mapID_, ref mapID);
            /*for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
            {
                mapID_.Add(mapID);
                DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
                er2.Write((sbyte)(f.Name.Length + 0x80));
                er2.Write(f.Name, Encoding.ASCII, false);
                er2.Write(mapID);
                er2.Write((byte)0xF0);
                mapID += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length+1);
            }
            for (int i = 0; i < Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
            {
                FileInfo f = new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
                er2.Write((sbyte)f.Name.Length);
                er2.Write(f.Name, Encoding.ASCII, false);
                items += 1;
            }
            for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
            {
                er2.Write((byte)0x00);
                er4.Write((Int32)er2.BaseStream.Position+(8 + (Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length * 0x8)));
                er4.Write(items);
                er4.Write((sbyte)0);//Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length);
                //er4.Write((byte)0x00);
                er4.Write((byte)0xF0);
                for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
                {
                    mapID2_.Add(mapID2);
                    DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
                    er2.Write((sbyte)(f.Name.Length + 0x80));
                    er2.Write(f.Name, Encoding.ASCII, false);
                    er2.Write(mapID2);
                    er2.Write((byte)0xF0);
                    mapID2 += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length+1);
                }
                if (i != Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length)
                {
                    mapID2 += 1;
                }
                for (int j = 0; j < Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
                {
                    FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
                    er2.Write((sbyte)f.Name.Length);
                    er2.Write(f.Name, Encoding.ASCII, false);
                    items += 1;
                }
                for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
                {
                    er2.Write((byte)0x00);
                    er4.Write((Int32)er2.BaseStream.Position + (8 + (Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length * 0x8)));
                    er4.Write(items);
                    er4.Write((sbyte)(mapID2_[j]));//Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length);
                    //er4.Write((byte)0x01);
                    er4.Write((byte)0xF0);
                    for (int k = 0; k < Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
                    {
                        mapID3_.Add(mapID3);
                        DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
                        er2.Write((sbyte)(f.Name.Length + 0x80));
                        er2.Write(f.Name, Encoding.ASCII, false);
                        er2.Write(mapID3);
                        er2.Write((byte)0xF0);
                        mapID3 += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k], "*.*", SearchOption.TopDirectoryOnly).Length+1);
                    }
                    for (int k = 0; k < Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
                    {
                        FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
                        er2.Write((sbyte)f.Name.Length);
                        er2.Write(f.Name, Encoding.ASCII, false);
                        items += 1;
                    }
                }
            }*/
            er2.Write((byte)0x00);
            while (true)
            {
                if (CountDecimalPlaces((float)er2.BaseStream.Length / 4F) == 0)
                {
                    break;
                }
                else
                {
                    er2.Write((byte)0xFF);
                }
            }
            er2.Close();
            er4.Close();
            er.Write("BTNF", Encoding.ASCII, false);
            er.Write((Int32)ms.ToArray().Length + ms3.ToArray().Length + 8);
            byte[] q2 = ms3.ToArray();
            er.Write(q2, 0, q2.Length);
            byte[] q = ms.ToArray();
            er.Write(q, 0, q.Length);
            //gmif
            MemoryStream ms2 = new MemoryStream();
            EndianBinaryWriter er3 = new EndianBinaryWriter(ms2, Endianness.LittleEndian);
			indir.writeFileData(ref er3);
            /*for (int i = 0; i < Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
            {
                FileInfo f = new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
                er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
                while (true)
                {
                    if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
                    {
                        break;
                    }
                    else
                    {
                        er3.Write((byte)0xFF);
                    }
                }
            }
            for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
            {
                for (int j = 0; j < Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
                {
                    FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
                    er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
                    while (true)
                    {
                        if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
                        {
                            break;
                        }
                        else
                        {
                            er3.Write((byte)0xFF);
                        }
                    }
                }
                for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
                {
                    for (int k = 0; k < Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
                    {
                        FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
                        er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
                        while (true)
                        {
                            if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
                            {
                                break;
                            }
                            else
                            {
                                er3.Write((byte)0xFF);
                            }
                        }
                    }
                }
            }*/
            er3.Close();
            er.Write("GMIF", Encoding.ASCII, false);
            er.Write((Int32)ms2.ToArray().Length + 8);
            byte[] q3 = ms2.ToArray();
            er.Write(q3, 0, q3.Length);
            er.BaseStream.Position = 8;
            er.Write((Int32)er.BaseStream.Length);
            er.Close();
        }
		public static void pack(string indir, string outfile)
		{
			File.Delete(outfile);
			EndianBinaryWriter er = new EndianBinaryWriter(File.OpenWrite(outfile), Endianness.LittleEndian);
			//header
			er.Write("NARC", Encoding.ASCII, false);
			er.Write(new byte[] { 0xFE, 0xFF, 0x00, 0x01 }, 0, 4);
			er.Write((Int32)0); //write later
			er.Write((Int16)16);
			er.Write((Int16)3);
			//btaf
			er.Write("BTAF", Encoding.ASCII, false);
			Int32 numfiles = Directory.GetFiles(indir, "*.*", SearchOption.AllDirectories).Length;
			er.Write((Int32)0xC + (numfiles * 8));
			er.Write(numfiles);
			int pos = 0;
			for (int i = 0; i < numfiles; i++)
			{
				er.Write((Int32)pos);
				pos += (Int32)(new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.AllDirectories)[i]).Length);
				er.Write((Int32)pos);
				while (true)
				{
					if (CountDecimalPlaces((float)pos / 4F) == 0)
					{
						break;
					}
					else
					{
						pos += 1;
					}
				}
			}
			//BTNF
			MemoryStream ms = new MemoryStream();
			EndianBinaryWriter er2 = new EndianBinaryWriter(ms, Endianness.LittleEndian);
			MemoryStream ms3 = new MemoryStream();
			EndianBinaryWriter er4 = new EndianBinaryWriter(ms3, Endianness.LittleEndian);
			er4.Write((Int32)(8 + (Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length * 0x8)));
			er4.Write((Int16)0);
			er4.Write((Int16)(Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length + 1));
			List<sbyte> mapID_ = new List<sbyte>();
			List<sbyte> mapID2_ = new List<sbyte>();
			List<sbyte> mapID3_ = new List<sbyte>();
			sbyte mapID = 1;
			sbyte mapID2 = 2;
			sbyte mapID3 = 3;
			Int16 items = 0;
			for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
			{
				mapID_.Add(mapID);
				DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
				er2.Write((sbyte)(f.Name.Length + 0x80));
				er2.Write(f.Name, Encoding.ASCII, false);
				er2.Write(mapID);
				er2.Write((byte)0xF0);
				mapID += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length + 1);
			}
			for (int i = 0; i < Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
			{
				FileInfo f = new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
				er2.Write((sbyte)f.Name.Length);
				er2.Write(f.Name, Encoding.ASCII, false);
				items += 1;
			}
			for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
			{
				er2.Write((byte)0x00);
				er4.Write((Int32)er2.BaseStream.Position + (8 + (Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length * 0x8)));
				er4.Write(items);
				er4.Write((sbyte)0);//Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length);
				//er4.Write((byte)0x00);
				er4.Write((byte)0xF0);
				for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
				{
					mapID2_.Add(mapID2);
					DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
					er2.Write((sbyte)(f.Name.Length + 0x80));
					er2.Write(f.Name, Encoding.ASCII, false);
					er2.Write(mapID2);
					er2.Write((byte)0xF0);
					mapID2 += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length + 1);
				}
				if (i != Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length)
				{
					mapID2 += 1;
				}
				for (int j = 0; j < Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
				{
					FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
					er2.Write((sbyte)f.Name.Length);
					er2.Write(f.Name, Encoding.ASCII, false);
					items += 1;
				}
				for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
				{
					er2.Write((byte)0x00);
					er4.Write((Int32)er2.BaseStream.Position + (8 + (Directory.GetDirectories(indir, "*.*", SearchOption.AllDirectories).Length * 0x8)));
					er4.Write(items);
					er4.Write((sbyte)(mapID2_[j]));//Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length);
					//er4.Write((byte)0x01);
					er4.Write((byte)0xF0);
					for (int k = 0; k < Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
					{
						mapID3_.Add(mapID3);
						DirectoryInfo f = new DirectoryInfo(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
						er2.Write((sbyte)(f.Name.Length + 0x80));
						er2.Write(f.Name, Encoding.ASCII, false);
						er2.Write(mapID3);
						er2.Write((byte)0xF0);
						mapID3 += (sbyte)(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k], "*.*", SearchOption.TopDirectoryOnly).Length + 1);
					}
					for (int k = 0; k < Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
					{
						FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
						er2.Write((sbyte)f.Name.Length);
						er2.Write(f.Name, Encoding.ASCII, false);
						items += 1;
					}
				}
			}
			er2.Write((byte)0x00);
			while (true)
			{
				if (CountDecimalPlaces((float)er2.BaseStream.Length / 4F) == 0)
				{
					break;
				}
				else
				{
					er2.Write((byte)0xFF);
				}
			}
			er2.Close();
			er4.Close();
			er.Write("BTNF", Encoding.ASCII, false);
			er.Write((Int32)ms.ToArray().Length + ms3.ToArray().Length + 8);
			byte[] q2 = ms3.ToArray();
			er.Write(q2, 0, q2.Length);
			byte[] q = ms.ToArray();
			er.Write(q, 0, q.Length);
			//gmif
			MemoryStream ms2 = new MemoryStream();
			EndianBinaryWriter er3 = new EndianBinaryWriter(ms2, Endianness.LittleEndian);
			for (int i = 0; i < Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
			{
				FileInfo f = new FileInfo(Directory.GetFiles(indir, "*.*", SearchOption.TopDirectoryOnly)[i]);
				er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
				while (true)
				{
					if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
					{
						break;
					}
					else
					{
						er3.Write((byte)0xFF);
					}
				}
			}
			for (int i = 0; i < Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly).Length; i++)
			{
				for (int j = 0; j < Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
				{
					FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j]);
					er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
					while (true)
					{
						if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
						{
							break;
						}
						else
						{
							er3.Write((byte)0xFF);
						}
					}
				}
				for (int j = 0; j < Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly).Length; j++)
				{
					for (int k = 0; k < Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly).Length; k++)
					{
						FileInfo f = new FileInfo(Directory.GetFiles(Directory.GetDirectories(Directory.GetDirectories(indir, "*.*", SearchOption.TopDirectoryOnly)[i], "*.*", SearchOption.TopDirectoryOnly)[j], "*.*", SearchOption.TopDirectoryOnly)[k]);
						er3.Write(File.ReadAllBytes(f.FullName), 0, (int)f.Length);
						while (true)
						{
							if (CountDecimalPlaces((float)er3.BaseStream.Length / 4F) == 0)
							{
								break;
							}
							else
							{
								er3.Write((byte)0xFF);
							}
						}
					}
				}
			}
			er3.Close();
			er.Write("GMIF", Encoding.ASCII, false);
			er.Write((Int32)ms2.ToArray().Length + 8);
			byte[] q3 = ms2.ToArray();
			er.Write(q3, 0, q3.Length);
			er.BaseStream.Position = 8;
			er.Write((Int32)er.BaseStream.Length);
			er.Close();
		}
        public static int CountDecimalPlaces(double double1)
        {
            if (double1.ToString().Contains(","))
            {
                return double1.ToString().Remove(0, double1.ToString().IndexOf(",") + 1).Length;
            }
            else
            {
                return 0;
            }
        }
 
    }
}
